/*******************************************************************************
 * http restful 接口调用通用api 并增加简化调用 restful api接口的方法
 ******************************************************************************/
var requestcount = 0;
!function($) {
	// 判断对象是否为function
	var isFunction = function(it) {
		var t = typeof it; // must evaluate separately due to bizarre Opera
		// bug. See #8937
		return it && (t == "function" || it instanceof Function); // Boolean
	}
	// 判断对象是否为数组
	var isArray = function(/* anything */it) {
		return it && (it instanceof Array || typeof it == "array"); // Boolean
	}
	// 判断对象是否为对象
	var isObject = function(/* anything */it) {
		return it !== undefined && (it === null || typeof it == "object" || isArray(it) || isFunction(it)); // Boolean
	}

	/***************************************************************************
	 * rest请求返回对象
	 **************************************************************************/
	var Deferred = {
		renderForm : function(form) {
			return this.done(function() {
				if (arguments.length > 0) {
					var returnData = arguments[0];
					if (isArray(returnData)) {
						$(form).bindData(returnData.length == 0 ? {} : returnData[0]);
					} else if (isObject(returnData)) {
						$(form).bindData(returnData);
					}
				}
			});
		},
		renderGrid : function(grid) {
			return this.done(function() {
				if (arguments.length > 0) {
					var returnData = arguments[0];
					if (isArray(returnData) || (returnData.total != 'undefined' && isArray(returnData.rows))) {
						$(grid).bootstrapTable('load', returnData);
					}
				}
			});
		},
		ClientAlways : function(response) {
			var type = $.type(response);

			var isJson = function(str) {
				var filtered = str.replace(/\\["\\\/bfnrtu]/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, '');

				if (/^[\],:{}\s]*$/.test(filtered)) {
					return true;
				}
				return false;
			};

			var jsonData = null;
			switch (type) {
			case 'string':
				if (isJson(response)) {
					jsonData = $.evalJSON(response);
				} else {
					jsonData = response || {};
				}
				break;
			case 'object':
				if (response.responseText && isJson(response.responseText)) {
					jsonData = $.evalJSON(response.responseText);
				} else {
					if (response.responseText) {
						jsonData = {
							result_code : '-1',
							result_msg : response.responseText
						};
					} else {
						jsonData = response;
					}

				}
				break;
			default:
				jsonData = response || {};
			}
			// modify by changcheng 解决模态框中弹窗层级相互遮盖的BUG START
			if (jsonData.code == '-2') {
				var template = "<form class='form-horizontal'><fieldset><div class='form-group'><span class='col-sm-3 control-span' style='width:140px'>错误详细原因：</span><div class='col-sm-9'/></div><div class='form-group'><div class='col-sm-12'><textarea class='form-control' readonly='readonly' rows='10'>{message}</textarea></div></div></fieldset></form>";
				var errorMsg = $.replacePlaceholder(template, jsonData)
				
				BootstrapDialog.show({
					title : '系统错误',
					cssClass : 'dialog-index',
					message : errorMsg,
					buttons : [ {
						label : '确定',
						cssClass : 'btn-primary',
						action : function(dialog) {
							dialog.close();
						}
					} ]
				});
			}else if(jsonData.code == '-1'){
				customAlertDialog(jsonData.message, '系统提示', null, null);
			}
			// modify by changcheng 解决模态框中弹窗层级相互遮盖的BUG END
			requestcount -= 1;
			if(requestcount <= 0){
			    $("#fakeLoader").css("display","none");
			}
		}
	}

	// 扩展jquery deferred
	$._Deferred = $.Deferred;
	$.Deferred = function(param) {
		var deferredToExtend = $._Deferred(param);
		$.extend(deferredToExtend, Deferred);
		return deferredToExtend;
	}

	// 扩展jquery ajax
	$._ajax = $.ajax;
	$.ajax = function(param) {
		var ajaxToExtend = $._ajax(param);
		$.extend(ajaxToExtend, Deferred);
		return ajaxToExtend;
	}

	/***************************************************************************
	 * rest Client对象 uri rest uri contentType 默认:application/json encoding
	 * 默认:UTF-8
	 **************************************************************************/
	var RestClient = function(uri, contentType, encoding, async) {
		/***********************************************************************
		 * rest Client对象默认参数
		 **********************************************************************/
		var DEFAULTS = {
			type : 'GET',
			contentType : 'application/json',
			encoding : 'UTF-8',
			dataType : 'json',
			async : true,
			autoErrorComplete : true,
			headers : {},
			queryParams : {}
		}

		this.options = $.extend({}, DEFAULTS, {
			uri : uri,
			contentType : contentType,
			encoding : encoding,
			async : async
		});
	}

	// 设置rest请求header,调用方法举例：setOptions('name', 'value')或setOptions({'name':
	// 'value'})
	RestClient.prototype.setOptions = function(Option) {
		if ((typeof header == 'string') && (arguments.length == 2)) {
			this.options[arguments[0]] = arguments[1];
		} else {
			$.extend(this.options, Option);
		}
		return this;
	}

	// 设置rest请求header,调用方法举例：setHeader('name', 'value')或setHeader({'name':
	// 'value'})
	RestClient.prototype.setHeader = function(header) {
		if ((typeof header == 'string') && (arguments.length == 2)) {
			this.options.headers[arguments[0]] = arguments[1];
		} else {
			$.extend(this.options.headers, header);
		}
		return this;
	}
	// 设置rest请求查询条件，包括rest中的占位符的替换
	// params可以为json对象、key/value字符串、也可以为form对象，通过判断params的参数类型及参数个数来动态确定调用方法
	// uri占位符的值替换是通过读取params里对应值来替换的，uri占位符也可以通过get、post等方法中的params来替换
	RestClient.prototype.setQuery = function(/* 可以为json对象、key/value字符串、也可以为form对象 */params) {
		if (typeof params == 'string') {
			if (arguments.length == 2) {
				this.options.queryParams[arguments[0]] = arguments[1];
			} else {
				this.setQuery($(params).collect());
			}
		} else if (params.nodeType || params instanceof jQuery) {
			this.setQuery($(params).collect());
		} else {
			$.extend(this.options.queryParams, params);
		}
		return this;
	}

	// uri字符替换和生成
	RestClient.prototype.dealUri = function(data) {
		var rest = this;

		var usedParams = [];

		var _data = isArray(data) ? {} : data;
		$.each(rest.options.queryParams, function(key, value) {
			delete _data[key];
		});

		// 确定替换映射对象
		var queryParams = $.extend({}, isArray(data) ? {} : data, rest.options.queryParams);
		// 替换queryParams中的占位符
		$.each(rest.options.queryParams, function(key, value) {
			if (typeof value == 'string') {
				queryParams[key] = rest.options.queryParams[key] = $.replacePlaceholder(value, queryParams, usedParams);
			}
		});
		// 替换uri中的占位符
		var uri = $.replacePlaceholder(rest.options.uri, queryParams, usedParams);
		// 删除替换到uri、queryParams中的键值
		$.each(usedParams, function(index, key) {
			delete rest.options.queryParams[key];
		});

		var url = uri.split('?');
		var query = [];
		// 将uri中？后的内容重新返回queryParams中
		if (url.length > 1) {
			$.each(url[1].split('&'), function(i, param) {
				param = param.split('=');
				rest.options.queryParams[param[0]] = (param.length == 1 ? '' : param[1]);
			});
		}
		// 对queryParams处理成key=value&key2=vaule2.。。结构，并对value进行编码
		var params = $.param(rest.options.queryParams);
		return url[0] + (params == '' ? '' : ('?' + params));
	}

	// rest client核心处理方法
	// type 请求类型如：GET\POST\PUT\DELETE等
	// params 请求参数，GET时携带在url中，其他的在body中携带，如果为null 则body不传内容
	// beforeSend 对params、RestClient参数进行调整，返回值为最终的params
	RestClient.prototype.send = function(type, params, beforeSend) {
    	requestcount += 1;
    	if(requestcount > 0){
    	    $("#fakeLoader").css("display","block");
    	}
		this.options.type = type;
		if (params && (typeof params == 'string' || params.nodeType || params instanceof jQuery)) {
			var ch = params.charAt(0)
			if (!(ch == '{' || ch == '<') && $(params).size() == 1) {
				params = $(params).collect() || {};
			}
		}
		if (!params)
			params = {};
		if (beforeSend)
			params = beforeSend(params, this.options);

		var processData = true;
		var data = {};
		if (params){
			data = params;
		}
		if(type != 'GET' && type != 'DELETE' && 'application/x-www-form-urlencoded' != this.options.contentType){
			processData = false;
		}

		var url = this.dealUri(data);

		var type = $.type(data);
		if ((type == 'object' || type == 'array') && processData == false && data != null) {
			data = $.toJSON(data);
			if (data == "{}") {
				data = null;
			}
		}

		// 设置编码格式
		var contentType = this.options.contentType + '; charset=' + this.options.encoding;
		var deferred = $.ajax($.extend({}, this.options, {
			url : url,
			contentType : contentType,
			processData : processData,
			data : data
		}));

		if (this.options.autoErrorComplete) {
			deferred = deferred.always(Deferred.ClientAlways);
		}
		return deferred;
	}

	RestClient.prototype.uploadForm = function(form, beforeSend, method) {
		requestcount += 1;
    	if(requestcount > 0){
    	    $("#fakeLoader").css("display","block");
    	}
    	
		var dtd = $.Deferred();
		if (!method) {
			method = "POST";
		}
		method = method.toUpperCase();

		var data = $(form).collect() || {};
		if (beforeSend)
			data = beforeSend(data, this.options);

		var url = this.dealUri(data);

		var iframe = $('#_uploadFromIframe');
		if (iframe.size() == 0) {
			iframe = $("<iframe id='_uploadFromIframe' name='_uploadFromIframe' style='border:0px;' width=0 height=0></iframe>").prependTo('body');
			iframe.load(function() {
				var text = '';
				try{
					text = $(this.contentWindow.document.body).text();
				}catch(e){
					text = '' + e;
				}
				$(this).data('dtd').resolve(/^(\[.*\])|(\{.*\})$/.test(text) ? $.evalJSON(text) : text);
			});
		}
		iframe.data('dtd', dtd);

		var _form = $('#_uploadFrom');
		if (_form.size() > 0) {
			_form.empty();
		} else {
			_form = $('<form id="_uploadFrom" enctype="multipart/form-data" method="POST" target="_uploadFromIframe"></form>').prependTo('body').hide();
		}

		$.each(data, function(key, value) {
			$('<input name="' + key + '" value="' + encodeURIComponent(value) + '"></input>').prependTo(_form);
		});

		var files = []
		var hfiles = []
		$(':file', form).each(function() {
			if (this.value) {
				var hfile = $('<span/>');
				hfiles.push(hfile);
				
				var file = $(this);
				file.after(hfile);
				
				file.prependTo(_form);
				files.push(this);
			}
		});

		if (method != "POST") {
			if (url.indexOf('?') > 0) {
				url += "&__method=" + method;
			} else {
				url += "?__method=" + method;
			}
		}

		_form.attr('action', url);
		_form.submit();
		return dtd.promise().always(function(){
			$.each(hfiles, function(i, file){
				file.replaceWith(files[i])
			})
		}).always(Deferred.ClientAlways);
	}

	// rest client get方法调用
	// params 请求参数，GET时携带在url中
	// beforeSend 对params、RestClient参数进行调整，返回值为最终的params
	RestClient.prototype.get = function(/* 查询参数或form */params, /* 发送前对params进行处理 */beforeSend) {
		if (isFunction(params)) {
			return this.send('GET', null, params);
		}
		return this.send('GET', params, beforeSend);
	}
	// rest client post方法调用
	// params 请求参数，其他的在body中携带，如果为null 则body不传内容
	// beforeSend 对params、RestClient参数进行调整，返回值为最终的params
	RestClient.prototype.post = function(jsonObj, beforeSend) {
		return this.send('POST', jsonObj, beforeSend);
	}
	// rest client put方法调用
	// params 请求参数，其他的在body中携带，如果为null 则body不传内容
	// beforeSend 对params、RestClient参数进行调整，返回值为最终的params
	RestClient.prototype.put = function(jsonObj, beforeSend) {
		return this.send('PUT', jsonObj, beforeSend);
	}
	// rest client delete方法调用
	// params 请求参数，其他的在body中携带，如果为null 则body不传内容
	// beforeSend 对params、RestClient参数进行调整，返回值为最终的params
	RestClient.prototype.del = function(params, beforeSend) {
		if (isFunction(params)) {
			return this.send('DELETE', null, params);
		}
		return this.send('DELETE', params, beforeSend);
	}

	// 定义3个jquery扩展接口:
	// getRestClient 通用restful接口调用方法
	// getApiClient 调用hm api通用方法
	// replacePlaceholder 占位符替换方法类
	$.extend({
		getRestClient : function(uri, async, contentType, encoding) {
			return new RestClient(path + uri, contentType, encoding, async).setQuery({
				'rand' : Math.random()
			});
		},
		getApiClient : function(uri, async, contentType, encoding) {
			return new RestClient(path + '/api'+ uri, contentType, encoding, async).setHeader('cache', '0').setQuery({
				'rand' : Math.random()
			});
		},
		replacePlaceholder : function(uri, params, usedParams) {
			params = params || {};
			return uri.replace(/\{(.+?)\}/g, function(m, i) {
				var value = params[i] == null ? '' : params[i];
				if (usedParams)
					usedParams.push(i);
				return value;
			});
		}
	});
}(jQuery);